iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0
Software Development

Windows Driver + Electron 學習筆記系列 第 7

Day07 非隨插即用(Non-PnP)驅動程式-3

  • 分享至 

  • xImage
  •  

今天介紹Non-PnP dirver sample中用來安裝及測試驅動程式的windows console app,應用程式主體為testapp.c,相關函式定義在install.c,這個應用程式有安裝及移除驅動程式的流程,下面依序介紹。

在main函式裡首先會嘗試用先前定義的裝置名稱去建立檔案,之後會以檔案的形式去存取裝置。

    //
    // open the device
    //
    hDevice = CreateFile(DEVICE_NAME,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         NULL,
                         CREATE_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL,
                         NULL);

如果開啟失敗,則去讀取錯誤碼,確定是不是檔案未找到或路徑未找到,如果是的話則繼續進行安裝驅動程式的步驟。

        errNum = GetLastError();

        if (!(errNum == ERROR_FILE_NOT_FOUND ||
                errNum == ERROR_PATH_NOT_FOUND)) {

            printf("CreateFile failed!  ERROR_FILE_NOT_FOUND = %d\n",
                   errNum);
            return ;
        }

SetupDriverName會將Non-PnP驅動程式複製到%windir%\system32\drivers

        //
        // The driver is not started yet so let us install the driver.
        // First setup full path to driver name.
        //
        ok = SetupDriverName( driverLocation, MAX_PATH );

再來進入ManageDriver

        ok = ManageDriver( DRIVER_NAME,
                           driverLocation,
                           DRIVER_FUNC_INSTALL );

由於ManageDriver傳入的參數是DRIVER_FUNC_INSTALL,會進行InstallDriver

            //
            // Install the driver service.
            //

            if (InstallDriver(schSCManager,
                              DriverName,
                              ServiceName
                              )) {

InstallDriver內會先開啟Service Control Manager

    //
    // Connect to the Service Control Manager and open the Services database.
    //

    schSCManager = OpenSCManager(NULL,                   // local machine
                                 NULL,                   // local database
                                 SC_MANAGER_ALL_ACCESS   // access required
                                 );

再來使用上一步開啟的Service Control Manager去建立服務DriverName為之前在public.h定義的名稱。

    schService = CreateService(SchSCManager,           // handle of service control manager database
                               DriverName,             // address of name of service to start
                               DriverName,             // address of display name
                               SERVICE_ALL_ACCESS,     // type of access to service
                               SERVICE_KERNEL_DRIVER,  // type of service
                               SERVICE_DEMAND_START,   // when to start service
                               SERVICE_ERROR_NORMAL,   // severity if service fails to start
                               ServiceExe,             // address of name of binary file
                               NULL,                   // service does not belong to a group
                               NULL,                   // no tag requested
                               NULL,                   // no dependency names
                               NULL,                   // use LocalSystem account
                               NULL                    // no password for service account
                               );

建立服務完成後進入StartDriver

                //
                // Start the driver service (i.e. start the driver).
                //

                rCode = StartDriver(schSCManager,
                                    DriverName
                                    );

StartDriver會先開啟服務,也是利用DriverName去開啟。

    //
    // Open the handle to the existing service.
    //
    schService = OpenService(SchSCManager,
                             DriverName,
                             SERVICE_ALL_ACCESS
                             );

最後則是啟動服務讓裝置能讓應用程式使用。

    //
    // Start the execution of the service (i.e. start the driver).
    //
    ok = StartService( schService, 0, NULL );

以上安裝驅動程式結束後,就會來到DoIoctls,此函式為測試驅動程式的主要函式。

    DoIoctls(hDevice);

這裡我們以METHOD_BUFFERED介紹,DeviceIoControl會對裝置傳入自行定義的IO control code,並傳入InputBufferOutputBufferbytesReturned,驅動程式的EvtIoDeviceControl就會依據IO control code對InputBufferOutputBuffer做對應的動作。

    //
    // Performing METHOD_BUFFERED
    //

    if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),
        "this String is from User Application; using METHOD_BUFFERED"))){
        return;
    }

    printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n");

    memset(OutputBuffer, 0, sizeof(OutputBuffer));

    bRc = DeviceIoControl ( hDevice,
                            (DWORD) IOCTL_NONPNP_METHOD_BUFFERED,
                            InputBuffer,
                            (DWORD) strlen( InputBuffer )+1,
                            OutputBuffer,
                            sizeof( OutputBuffer),
                            &bytesReturned,
                            NULL
                            );

在測試完成後就將裝置關閉

    //
    // Close the handle to the device before unloading the driver.
    //
    CloseHandle ( hDevice );

然後接著傳入DRIVER_FUNC_REMOVEManageDriver移除驅動程式。

    //
    // Unload the driver.  Ignore any errors.
    //
    ManageDriver( DRIVER_NAME,
                  driverLocation,
                  DRIVER_FUNC_REMOVE );

首先停止驅動程式

            //
            // Stop the driver.
            //

            StopDriver(schSCManager,
                       DriverName
                       );

先嘗試將服務開啟。

    //
    // Open the handle to the existing service.
    //

    schService = OpenService(SchSCManager,
                             DriverName,
                             SERVICE_ALL_ACCESS
                             );

若服務可以開啟就利用ControlService配合參數SERVICE_CONTROL_STOP停止服務

    //
    // Request that the service stop.
    //

    if (ControlService(schService,
                       SERVICE_CONTROL_STOP,
                       &serviceStatus
                       )) {

        //
        // Indicate success.
        //

        rCode = TRUE;

    } 

最後移除驅動程式

            //
            // Remove the driver service.
            //

            RemoveDriver(schSCManager,
                         DriverName
                         );

也是先嘗試將服務開啟。

    //
    // Open the handle to the existing service.
    //

    schService = OpenService(SchSCManager,
                             DriverName,
                             SERVICE_ALL_ACCESS
                             );

若服務可以開啟則刪除服務

    //
    // Mark the service for deletion from the service control manager database.
    //

    if (DeleteService(schService)) {

        //
        // Indicate success.
        //

        rCode = TRUE;

    } 

以上就是針對Non-PnP測試程式中,安裝及移除Non-PnP驅動程式的流程,這個流程對之後實作動態連結函庫(DLL)非常有幫助。

參考內容

啟動服務 - Win32 apps | Microsoft Learn


上一篇
Day06 非隨插即用(Non-PnP)驅動程式-2
下一篇
Day08 非隨插即用(Non-PnP)驅動程式-4
系列文
Windows Driver + Electron 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言